function varargout = TLCounteralarmDlg(action,varargin)

% TL_COUNTERALARM_DLG manages the user interface of TargetLink CounterAlarm block
%
% SYNTAX dlgInfo = TLCounteralarmDlg('GetDlgInfo');
%   gets dialog info of TargetLink CounterAlarm block
%
%   INPUT ARGUMENTS
%   -/-      
%
%   OUTPUT ARGUMENTS
%   dlgInfo     dialog information contains pageNames etc.
%
% SYNTAX [sheetDims, ctrlPos] = TLCounteralarmDlg('CtrlPositions', pageName, commonGeom, dlgInfo, sheetDims);
%   calculates the control positions of all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   commonGeom      common geometry data
%   dlgInfo         dialog information contains pageNames etc.
%   sheetDims       dimension of sheet
%
%   OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% SYNTAX dlgdata = TLCounteralarmDlg('Create', pageName, dlgfig, dlgdata);
%   creates all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX [dlgdata,bModified] = TLCounteralarmDlg('Manage', pageName, dlgfig, dlgdata, pageAction);
%   manages all actions of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageAction      modified control of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%   bModified       flag = 1, if dialog data are modified, =0 otherwise
%
% SYNTAX dlgdata = TLCounteralarmDlg('Update', dlgfig, dlgdata, pageNum);
%   updates all controls of dialog page: <pageNum>
%
%   INPUT ARGUMENTS
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageNum         number of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX TLCounteralarmDlg('Apply', dlgfig, dlgdata);
%   writes current blockdata to block and DD
%
%   INPUT ARGUMENTS
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
%   OUTPUT ARGUMENTS
%   - / -


% Author(s): D. Andoleit, T. Pietzsch
% $RCSfile: TLCounteralarmDlg.m $
% $ProjectName: e:/ARC/Components/HostSW/SimulinkBlocksets/TLBlocksets/MultirateBlockset/MultirateBlockset_UI/Sources/MSrc/project.pj $
% $Revision: 1.15 $
% $Date: 2011/08/30 12:42:39MESZ $
%
% Copyright ?2011 dSPACE GmbH. All rights reserved.


switch action
    case 'GetDlgInfo'
        hBlock = varargin{1};
        dlgInfo = tl_get_dlginfodefaults('rtos');
        titleName = 'Counter/Alarm';
        pathinfo = tl_pathinfo(hBlock);
        dlgInfo.title = sprintf('TargetLink %s: %s', titleName, pathinfo.shortDisplayName);
        dlgInfo.bSLParamDlg = 1;
        dlgInfo.pageNames   = {
            'Alarms'};
        varargout{1} = dlgInfo;
        varargout{2} = get_tlcg_data(hBlock);

    case 'CtrlPositions'
        pageName     = varargin{1};
        commonGeom   = varargin{2};
        sheetDims    = varargin{4};
        switch pageName
            case 'Alarms'
                [sheetDims, ctrlPos] = FcnCalcCounterAlarmControlPositions(commonGeom);
        end
        varargout{1} = sheetDims;
        varargout{2} = ctrlPos;

    case 'Create',
        pageName = varargin{1};
        dlgfig   = varargin{2};
        dlgdata  = varargin{3};
        pageNum  = strmatch(pageName, dlgdata.pageNames, 'exact');
        switch pageName
            case 'Alarms'
                dlgdata = FcnCreateCounterAlarmControls(pageNum,dlgfig,dlgdata);
        end
        dlgdata.pageData{pageNum}.ctrlPos = [];
        varargout{1} = dlgdata;

    case 'Manage',
        pageName   = varargin{1};
        dlgfig     = varargin{2};
        dlgdata    = varargin{3};
        pageAction = varargin{4};
        pageNum    = strmatch(pageName,dlgdata.pageNames,'exact');
        switch pageName
            case 'Alarms'
                [dlgdata, bModified] = ...
                    FcnManageCounterAlarmControls(pageNum,dlgfig,dlgdata,pageAction);
        end
        varargout{1} = dlgdata;
        varargout{2} = bModified;

    case 'Update'
        dlgfig    = varargin{1};
        dlgdata   = varargin{2};
        pageNum   = varargin{3};

        pageName  = dlgdata.pageNames{pageNum};

        switch pageName
            case 'Alarms'
                dlgdata = FcnUpdateCounterAlarmControls(dlgdata, dlgfig, pageNum);
        end
        varargout{1} = dlgdata;

    case 'Apply'
        dlgdata = varargin{2};
        bClose   = varargin{3};
        FcnApply(dlgdata);
        [dlgdata, bClose] = tl_apply_blockdata(dlgdata, bClose);
        varargout{1} = dlgdata;
        varargout{2} = bClose;

    otherwise
        error(['Invalid action: "' action '"']);
end


%-----------------------------------------------------------------------------------------
% FcnCalcCounterAlarmControlPositions calculates positions for all controls on alarm page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-----------------------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnCalcCounterAlarmControlPositions(commonGeom)

strings_and_styles = {...
    'Tick duration in simulation: ', 'text';...
    repmat('m',1,24),                'edit'; ...
    repmat('m',1,6),                'edit'; ...
    ' Delete Alarm ',                'pushbutton';...
    'Cancel alarm port width: ',     'text';...
    '123',                          'edit'; ...
    '+',                            'pushbutton'; ...
    'Automatic action assignment',  'checkbox'};

[alarmLabelSize, ...
    alarmPopupSize, ...
    ticksEditSize, ...
    deleteAlarmButtonSize, ...
    cancelAlarmLabelSize, ...
    cancelAlarmEditSize, ...
    upButtonSize, ...
    autoActionCheckboxSize] = ...
    ds_get_uicontrol_sizes(commonGeom, strings_and_styles);

widths = [ ...
    alarmLabelSize(1), ...      % max of label width in first column
    alarmPopupSize(1)];
[col,colWidth,colDelta,rowDelta] = ds_get_gui_columns(widths,commonGeom);

% define pixel width for a small gap
smallGap = colDelta/5;

% finetune some results
upButtonSize = upButtonSize * diag([1 0.5]);
if (2 * deleteAlarmButtonSize(1) + colDelta/3) > alarmPopupSize(1)
    alarmPopupSize(1) = 2 * deleteAlarmButtonSize(1) + colDelta/3;
else
    deleteAlarmButtonSize(1) = (alarmPopupSize(1) - colDelta/3) / 2;
end
ticksTextWidth = alarmPopupSize(1) - ticksEditSize(1) - smallGap;

%-----------------------------------------------------------
% counters group box
%-----------------------------------------------------------
cx = commonGeom.sheetSideEdgeBuffer + ...
    commonGeom.figSideEdgeBuffer;
cy = commonGeom.bottomSheetOffset + ...
    commonGeom.sheetBottomEdgeBuffer;

countersGroupboxWidth = col(end) + ...
    colWidth(end) + ...
    commonGeom.frameSideEdgeBuffer;

countersGroupboxHeight = ...
    commonGeom.frameTopEdgeBuffer + ...
    8 * rowDelta + ...
    9 * commonGeom.editHeight + ...
    commonGeom.frameBottomEdgeBuffer;
ctrlPos.countersGroupbox =  ...
    [cx cy  countersGroupboxWidth countersGroupboxHeight];

%-----------------------------------------------------------
% 9th row
cy = commonGeom.frameBottomEdgeBuffer;

% tick duration in simulation
cx = col(1);
ctrlPos.tickDurationInSimulationLabel = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.tickDurationInSimulationEdit = [cx cy ticksEditSize];

%-----------------------------------------------------------
% 8th row
cy = cy + alarmPopupSize(2) + rowDelta;

% tick duration
cx = col(1);
ctrlPos.tickDurationLabel = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.tickDurationEdit = [cx cy ticksEditSize];

cx = col(2) + ticksEditSize(1) + smallGap;
ctrlPos.tickDurationText = [cx cy ticksTextWidth commonGeom.textHeight];

%-----------------------------------------------------------
% 7th row
cy = cy + alarmPopupSize(2) + rowDelta;

% ticks per base
cx = col(1);
ctrlPos.ticksPerBaseLabel = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.ticksPerBaseEdit = [cx cy ticksEditSize];

%-----------------------------------------------------------
% 6th row
cy = cy + alarmPopupSize(2) + rowDelta;

% min cycle
cx = col(1);
ctrlPos.minCycleLabel = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.minCycleEdit = [cx cy ticksEditSize];

cx = col(2) + ticksEditSize(1) + smallGap;
ctrlPos.minCycleText = [cx cy ticksTextWidth commonGeom.textHeight];

%-----------------------------------------------------------
% 5th row
cy = cy + alarmPopupSize(2) + rowDelta;

% max allowed value
cx = col(1);
ctrlPos.maxAllowedValueLabel = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.maxAllowedValueEdit = [cx cy ticksEditSize];

cx = col(2) + ticksEditSize(1) + smallGap;
ctrlPos.maxAllowedValueText = [cx cy ticksTextWidth commonGeom.textHeight];

%-----------------------------------------------------------
% 4th row
cy = cy + autoActionCheckboxSize(2) + rowDelta;

% omit counter initialization checkbox
cx = col(2);
ctrlPos.omitCounterInitializationCheckbox = [cx cy autoActionCheckboxSize];

%-----------------------------------------------------------
% 3th row
cy = cy + autoActionCheckboxSize(2) + rowDelta;

% used as system timer checkbox
cx = col(2);
ctrlPos.usedAsSystemTimerCheckbox = [cx cy autoActionCheckboxSize];

%-----------------------------------------------------------
% 2nd row
cy = cy + autoActionCheckboxSize(2) + rowDelta;

% add counter push button
cx = col(2);
ctrlPos.addCounterButton = [cx cy deleteAlarmButtonSize];

% delete alarm push button
cx = col(2) + deleteAlarmButtonSize(1) + colDelta/3;
ctrlPos.deleteCounterButton = [cx cy deleteAlarmButtonSize];

%-----------------------------------------------------------
% 1st row
cy = cy + deleteAlarmButtonSize(2) + rowDelta;

% alarm label
cx = col(1);
ctrlPos.counterLabel = [cx cy alarmLabelSize];

% alarm edit
cx = col(2);
ctrlPos.counterPopup = [cx cy alarmPopupSize];

%-----------------------------------------------------------
% alarms group box
%-----------------------------------------------------------
cx = ctrlPos.countersGroupbox(1);
cy = ctrlPos.countersGroupbox(2) + ctrlPos.countersGroupbox(4) + commonGeom.textHeight;

alarmsGroupboxWidth = countersGroupboxWidth;

alarmsGroupboxHeight = ...
    commonGeom.frameTopEdgeBuffer + ...
    7 * rowDelta + ...
    8 * commonGeom.editHeight + ...
    commonGeom.frameBottomEdgeBuffer;
ctrlPos.alarmsGroupbox =  ...
    [cx cy  alarmsGroupboxWidth alarmsGroupboxHeight];

%-----------------------------------------------------------
% 8th row
cy = commonGeom.frameBottomEdgeBuffer;

% activate task radiobutton
cx = col(1);
ctrlPos.callbackRadiobutton = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.callbackEdit = [cx cy alarmPopupSize];

%-----------------------------------------------------------
% 7th row
cy = cy + alarmPopupSize(2) + rowDelta;

% set event radiobutton
cx = col(1);
ctrlPos.setEventRadiobutton = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.setEventPopup = [cx cy alarmPopupSize];

%-----------------------------------------------------------
% 6th row
cy = cy + alarmPopupSize(2) + rowDelta;

% activate task radiobutton
cx = col(1);
ctrlPos.activateTaskRadiobutton = [cx cy alarmLabelSize];

cx = col(2);
ctrlPos.activateTaskPopup = [cx cy alarmPopupSize];

%-----------------------------------------------------------
% 5th row
cy = cy + alarmPopupSize(2) + rowDelta;

% automatic action assignment checkbox
cx = col(1);
ctrlPos.autoActionAssignmentCheckbox = [cx cy autoActionCheckboxSize];

%-----------------------------------------------------------
% 4th row
cy = cy + autoActionCheckboxSize(2) + rowDelta;

% relative alarm kind radiobutton
cx = col(1);
ctrlPos.relAlarmRadiobutton = [cx cy alarmLabelSize];

% cancel alarm port witdh
cx = col(2);
ctrlPos.cancelAlarmLabel = [cx cy cancelAlarmLabelSize];

% cx is calculating backwards
cx = cx + colWidth(2) - cancelAlarmEditSize(1) - smallGap - upButtonSize(1);
ctrlPos.cancelAlarmEdit = [cx cy cancelAlarmEditSize];

cx = cx + cancelAlarmEditSize(1) + smallGap;
ctrlPos.cancelAlarmUpButton = [cx cy + 0.5 * commonGeom.editHeight upButtonSize];
ctrlPos.cancelAlarmDownButton = [cx cy upButtonSize];

%-----------------------------------------------------------
% 3th row
cy = cy + cancelAlarmEditSize(2) + rowDelta;

% absolute alarm kind radiobutton
cx = col(1);
ctrlPos.absAlarmRadiobutton = [cx cy alarmLabelSize];

% start alarm port witdh
cx = col(2);
ctrlPos.startAlarmLabel = [cx cy cancelAlarmLabelSize];

% cx is calculating backwards
cx = cx + colWidth(2) - cancelAlarmEditSize(1) - smallGap - upButtonSize(1);
ctrlPos.startAlarmEdit = [cx cy cancelAlarmEditSize];

cx = cx + cancelAlarmEditSize(1) + smallGap;
ctrlPos.startAlarmUpButton = [cx cy + 0.5 * commonGeom.editHeight upButtonSize];
ctrlPos.startAlarmDownButton = [cx cy upButtonSize];

%-----------------------------------------------------------
% 2nd row
cy = cy + cancelAlarmEditSize(2) + rowDelta;

% add alarm push button
cx = col(2);
ctrlPos.addAlarmButton = [cx cy deleteAlarmButtonSize];

% delete alarm push button
cx = col(2) + deleteAlarmButtonSize(1) + colDelta/3;
ctrlPos.deleteAlarmButton = [cx cy deleteAlarmButtonSize];

%-----------------------------------------------------------
% 1st row
cy = cy + deleteAlarmButtonSize(2) + rowDelta;

% alarm label
cx = col(1);
ctrlPos.alarmLabel = [cx cy alarmLabelSize];

% alarm edit
cx = col(2);
ctrlPos.alarmPopup = [cx cy alarmPopupSize];


% sheet dimensions
sheetDims(1) = ctrlPos.alarmsGroupbox(3) + ...
    2 * commonGeom.frameSideEdgeBuffer;

sheetDims(2) = ctrlPos.alarmsGroupbox(4) + ...
    commonGeom.textHeight + ...
    ctrlPos.countersGroupbox(4) + ...
    commonGeom.textHeight + ...
    commonGeom.sheetBottomEdgeBuffer;


%-----------------------------------------------------------------------------------------
% FcnCreateCounterAlarmControls creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateCounterAlarmControls(pageNum,dlgfig,dlgdata)

ctrlPos    = dlgdata.pageData{pageNum}.ctrlPos;
Children   = dlgdata.pageData{pageNum}.children;

% alarm groupbox
Children.alarmsGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Alarms'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.alarmsGroupbox);

% alarm popup
Children.alarmLabel = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'text', ...
    'String',             'Alarm name:', ...
    'Position',           ctrlPos.alarmLabel);

Children.alarmPopup = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'Popupmenu', ...
    'String',             ' ', ...
    'Position',           ctrlPos.alarmPopup);

% add / delete alarm button
Children.addAlarmButton = uicontrol( ...
    'Parent',            Children.alarmsGroupbox, ...
    'Style',             'pushbutton', ...
    'String',            'Add Alarm', ...
    'Position',          ctrlPos.addAlarmButton);

Children.deleteAlarmButton = uicontrol( ...
    'Parent',            Children.alarmsGroupbox, ...
    'Style',             'pushbutton', ...
    'String',            'Delete Alarm', ...
    'Position',          ctrlPos.deleteAlarmButton);

% alarm kind radiobutton
Children.relAlarmRadiobutton  = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'radiobutton', ...
    'String',             'Relative', ...
    'Position',           ctrlPos.relAlarmRadiobutton );

Children.absAlarmRadiobutton  = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'radiobutton', ...
    'String',             'Absolute', ...
    'Position',           ctrlPos.absAlarmRadiobutton );

% start alarm port width
Children.startAlarmLabel = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'text', ...
    'String',             'Start alarm port width:', ...
    'Position',           ctrlPos.startAlarmLabel);

Children.startAlarmEdit = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.startAlarmEdit);

Children.startAlarmUpButton = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '+', ...
    'Position',           ctrlPos.startAlarmUpButton);

Children.startAlarmDownButton = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '-', ...
    'Position',           ctrlPos.startAlarmDownButton);

% cancel alarm port width
Children.cancelAlarmLabel = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'text', ...
    'String',             'Cancel alarm port width:', ...
    'Position',           ctrlPos.cancelAlarmLabel);

Children.cancelAlarmEdit = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.cancelAlarmEdit);

Children.cancelAlarmUpButton = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '+', ...
    'Position',           ctrlPos.cancelAlarmUpButton);

Children.cancelAlarmDownButton = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '-', ...
    'Position',           ctrlPos.cancelAlarmDownButton);

% automatic action assignment
Children.autoActionAssignmentCheckbox = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Automatic action assignment', ...
    'Position',           ctrlPos.autoActionAssignmentCheckbox);

Children.activateTaskRadiobutton  = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'radiobutton', ...
    'String',             'Activate Task', ...
    'Position',           ctrlPos.activateTaskRadiobutton);

Children.setEventRadiobutton  = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'radiobutton', ...
    'String',             'Set Event', ...
    'Position',           ctrlPos.setEventRadiobutton);

Children.callbackRadiobutton  = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'Style',              'radiobutton', ...
    'String',             'Callback', ...
    'Position',           ctrlPos.callbackRadiobutton);

Children.activateTaskPopup = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'Popupmenu', ...
    'String',             ' ', ...
    'Position',           ctrlPos.activateTaskPopup);

Children.setEventPopup = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'Popupmenu', ...
    'String',             ' ', ...
    'Position',           ctrlPos.setEventPopup);

Children.callbackEdit = uicontrol( ...
    'Parent',             Children.alarmsGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.callbackEdit);

%-------------------------------------------------------------------------------
% counter groupbox
Children.countersGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Counters'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.countersGroupbox);

% counter popup
Children.counterLabel = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'Counter name:', ...
    'Position',           ctrlPos.counterLabel);

Children.counterPopup = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'Popupmenu', ...
    'String',             ' ', ...
    'Position',           ctrlPos.counterPopup);

% add / delete counter button
Children.addCounterButton = uicontrol( ...
    'Parent',            Children.countersGroupbox, ...
    'Style',             'pushbutton', ...
    'String',            'Add Counter', ...
    'Position',          ctrlPos.addCounterButton);

Children.deleteCounterButton = uicontrol( ...
    'Parent',            Children.countersGroupbox, ...
    'Style',             'pushbutton', ...
    'String',            'Delete Counter', ...
    'Position',          ctrlPos.deleteCounterButton);

% counter checkbox
Children.usedAsSystemTimerCheckbox = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Used as system timer', ...
    'Position',           ctrlPos.usedAsSystemTimerCheckbox);

Children.omitCounterInitializationCheckbox = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Omit counter initialization', ...
    'Position',           ctrlPos.omitCounterInitializationCheckbox);

% max allowed value
Children.maxAllowedValueLabel = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'Max. allowed value:', ...
    'Position',           ctrlPos.maxAllowedValueLabel);

Children.maxAllowedValueEdit = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.maxAllowedValueEdit);

Children.maxAllowedValueText = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'x Tick duration = 0 s', ...
    'Position',           ctrlPos.maxAllowedValueText);

% min cycle
Children.minCycleLabel = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'Min. cycle:', ...
    'Position',           ctrlPos.minCycleLabel);

Children.minCycleEdit = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.minCycleEdit);

Children.minCycleText = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'x Tick duration = 0 s', ...
    'Position',           ctrlPos.minCycleText);

% ticks per base
Children.ticksPerBaseLabel = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'Ticks per base:', ...
    'Position',           ctrlPos.ticksPerBaseLabel);

Children.ticksPerBaseEdit = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.ticksPerBaseEdit);

% tick duration
Children.tickDurationLabel = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'Tick duration:', ...
    'Position',           ctrlPos.tickDurationLabel);

Children.tickDurationEdit = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.tickDurationEdit);

Children.tickDurationText = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             's', ...
    'Position',           ctrlPos.tickDurationText);

% tick duration in simulation
Children.tickDurationInSimulationLabel = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'Style',              'text', ...
    'String',             'Tick duration in simulation:', ...
    'Position',           ctrlPos.tickDurationInSimulationLabel);

Children.tickDurationInSimulationEdit = uicontrol( ...
    'Parent',             Children.countersGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           ctrlPos.tickDurationInSimulationEdit);

dlgdata.pageData{pageNum}.children = Children;

dlgdata = FcnGetDataFromDD(dlgdata);


%-----------------------------------------------------------------------------------------
% FcnManageCounterAlarmControls manage control actions of alarm page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageCounterAlarmControls(pageNum,dlgfig,dlgdata,pageAction)    %#ok

Children   = dlgdata.pageData{pageNum}.children;

% determine the current alarm control
currentAlarm      = dlgdata.data.alarm;
alarmList         = dlgdata.alarmInfo.dataStrings;
currentAlarmIdx   = find(strcmp(currentAlarm,alarmList));
% determine the current counter control
currentCounter     = dlgdata.alarmData(currentAlarmIdx).counterRef;
counterList        = dlgdata.counterInfo.dataStrings;
currentCounterIdx  = find(strcmp(currentCounter,counterList));

switch pageAction
    case 'counterPopup'
        % data are stored as properties of current counter
        currentCounterIdx = get(Children.counterPopup, 'Value');
        counterList = dlgdata.counterInfo.dataStrings;
        dlgdata.alarmData(currentAlarmIdx).counterRef = counterList{currentCounterIdx};
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
        bModified = 1;
    case 'addCounterButton'
        [dlgdata, bModified] = FcnAddCounter(dlgdata,currentAlarmIdx);
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
    case 'deleteCounterButton'
        dlgdata = FcnDeleteCounter(dlgdata,currentAlarmIdx);
        bModified = 1;
    case 'usedAsSystemTimerCheckbox'
        dlgdata.counterData(currentCounterIdx).usedassystemtimer = ...
            get(Children.usedAsSystemTimerCheckbox, 'Value');
        dlgdata.counterInfo.editedCounter = [dlgdata.counterInfo.editedCounter,currentCounter];
        bModified = 1;
    case 'omitCounterInitializationCheckbox'
        dlgdata.counterData(currentCounterIdx).omitcounterinitialization = ...
            get(Children.omitCounterInitializationCheckbox, 'Value');
        dlgdata.counterInfo.editedCounter = [dlgdata.counterInfo.editedCounter,currentCounter];
        bModified = 1;
    case 'maxAllowedValueEdit'
        dlgdata.counterData(currentCounterIdx).maxallowedvalue = ...
            eval(get(Children.maxAllowedValueEdit, 'String'));
        dlgdata.counterInfo.editedCounter = [dlgdata.counterInfo.editedCounter,currentCounter];
        bModified = 1;
    case 'minCycleEdit'
        dlgdata.counterData(currentCounterIdx).mincycle = ...
            eval(get(Children.minCycleEdit, 'String'));
        dlgdata.counterInfo.editedCounter = [dlgdata.counterInfo.editedCounter,currentCounter];
        bModified = 1;
    case 'ticksPerBaseEdit'
        dlgdata.counterData(currentCounterIdx).ticksperbase = ...
            eval(get(Children.ticksPerBaseEdit, 'String'));
        dlgdata.counterInfo.editedCounter = [dlgdata.counterInfo.editedCounter,currentCounter];
        bModified = 1;
    case 'tickDurationEdit'
        dlgdata.counterData(currentCounterIdx).tickduration = ...
            eval(get(Children.tickDurationEdit, 'String'));
        dlgdata.counterInfo.editedCounter = [dlgdata.counterInfo.editedCounter,currentCounter];
        bModified = 1;
    case 'tickDurationInSimulationEdit'
        dlgdata.data.tickdurationinsimulation = ...
            eval(get(Children.tickDurationInSimulationEdit, 'String'));
        bModified = 1;

    case 'alarmPopup'
        % data are stored as properties of current alarm
        currentAlarmIdx = get(Children.alarmPopup, 'Value');
        alarmList = get(Children.alarmPopup, 'String');
        dlgdata.data.alarm = alarmList{currentAlarmIdx};
        bModified = 1;
    case 'addAlarmButton'
        [dlgdata, bModified] = FcnAddAlarm(dlgdata);
    case 'deleteAlarmButton'
        dlgdata = FcnDeleteAlarm(dlgdata);
        bModified = 1;
    case 'absAlarmRadiobutton'
        dlgdata.data.alarmkind = 1;
        bModified = 1;
    case 'relAlarmRadiobutton'
        dlgdata.data.alarmkind = 2;
        bModified = 1;
    case {'startAlarmEdit','startAlarmUpButton','startAlarmDownButton'}
        [dlgdata.data.startalarmportwidth,bModified] = ds_handle_editupdown( ...
            dlgdata.data.startalarmportwidth, ...
            [Children.startAlarmEdit,Children.startAlarmUpButton,Children.startAlarmDownButton], ...
            gcbo,Inf);
    case {'cancelAlarmEdit','cancelAlarmUpButton','cancelAlarmDownButton'}
        [dlgdata.data.cancelalarmportwidth,bModified] = ds_handle_editupdown( ...
            dlgdata.data.cancelalarmportwidth, ...
            [Children.cancelAlarmEdit,Children.cancelAlarmUpButton,Children.cancelAlarmDownButton], ...
            gcbo,Inf);
    case 'autoActionAssignmentCheckbox'
        dlgdata.alarmData(currentAlarmIdx).autoactionassignment = ...
            get(Children.autoActionAssignmentCheckbox, 'Value');
        bModified = 1;
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
    case {'activateTaskRadiobutton','setEventRadiobutton','callbackRadiobutton'}
        actionKind = upper(pageAction(1:end-11));
        dlgdata.alarmData(currentAlarmIdx).actionkind = actionKind;
        bModified = 1;
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
    case 'activateTaskPopup'
        taskIdx = get(Children.activateTaskPopup, 'Value');
        taskList = get(Children.activateTaskPopup, 'String');
        dlgdata.alarmData(currentAlarmIdx).task = taskList{taskIdx};
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
        bModified = 1;
    case 'setEventPopup'
        eventIdx = get(Children.setEventPopup, 'Value');
        eventList = get(Children.setEventPopup, 'String');
        dlgdata.alarmData(currentAlarmIdx).event = eventList{eventIdx};
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
        bModified = 1;
    case 'callbackEdit'
        dlgdata.alarmData(currentAlarmIdx).callbackfcn = ...
            get(Children.callbackEdit, 'String');
        dlgdata.alarmInfo.editedAlarm = [dlgdata.alarmInfo.editedAlarm,currentAlarm];
        bModified = 1;
end


%--------------------------------------------------------------------------
% FcnAddCounter creates new counter with default data
%
% INPUT ARGUMENTS
%   dlgdata             dialog data
%   currentAlarmIdx     index of current alarm
%
% OUTPUT ARGUMENTS
%   dlgdata             modified dialog data
%   bModified           flag =1, if new counter is created, =0 otherwise
%--------------------------------------------------------------------------
function [dlgdata, bModified] = FcnAddCounter(dlgdata,currentAlarmIdx)

% initialize return value
bModified = 0;

% ask user for counter name
prompt   = 'Please enter a name for the counter.';
dlgTitle = 'Counter Name';
lineNum  = 1;
newCounterName = tl_deblank(char(inputdlg(prompt,dlgTitle,lineNum)),3);
if isempty(newCounterName),
    return;
end

counterData = dlgdata.counterData;

% check if counter is really new
counterNameList = dlgdata.counterInfo.dataStrings;
if any(strcmp(newCounterName,counterNameList));
    return
end

% check if current counter is invalid and can be overwritten
currentCounter    = dlgdata.alarmData(currentAlarmIdx).counterRef;
currentCounterIdx = find(strcmp(currentCounter,counterNameList));
if counterData(currentCounterIdx).bValid || strcmp(currentCounter, ' ')
    currentCounterIdx = length(counterNameList) + 1;
end
dlgdata.alarmData(currentAlarmIdx).counterRef = newCounterName;

% initialize properties to default
counterData = FcnSetCounterDefaults(counterData,currentCounterIdx);

% add new counter to counterlist
dlgdata.counterInfo.dataStrings(currentCounterIdx) = {newCounterName};

% append counter to list of new counters
dlgdata.counterInfo.addedCounter = unique([dlgdata.counterInfo.addedCounter,newCounterName]);
bModified = 1;

dlgdata.counterData = counterData;


%--------------------------------------------------------------------------
% FcnDeleteCounter remove current counter
%
% INPUT ARGUMENTS
%   dlgdata             dialog data
%   currentAlarmIdx     index of current alarm
%
% OUTPUT ARGUMENTS
%   dlgdata             modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnDeleteCounter(dlgdata,currentAlarmIdx)

counterData = dlgdata.counterData;
counterInfo = dlgdata.counterInfo;

% get relevant indices
counterList = counterInfo.dataStrings;
delCounter  = dlgdata.alarmData(currentAlarmIdx).counterRef;
delCounterIdx = find(strcmp(delCounter,counterList));

% add counters to list of deleted counters
counterInfo.deletedCounter = unique([counterInfo.deletedCounter,delCounter]);

% remove counter from list of added counters
idx = find(strcmp(delCounter,counterInfo.addedCounter));
if ~isempty(idx),
    counterInfo.addedCounter(idx) = [];
end

% purge property struct
counterInfo.dataStrings(delCounterIdx) = [];
counterData(delCounterIdx) = [];

% update current element
numElements = length(counterInfo.dataStrings);
if delCounterIdx > numElements,
    if numElements,
        % at least one element remained
        dlgdata.alarmData(currentAlarmIdx).counterRef = counterInfo.dataStrings{numElements};
    else
        % no elements
        dlgdata.alarmData(currentAlarmIdx).counterRef = ' ';
        counterInfo.dataStrings = {' '};
        counterData = FcnSetCounterDefaults([],1);
        counterData(1).bValid = 0;
    end
else
    dlgdata.alarmData(currentAlarmIdx).counterRef = counterInfo.dataStrings{delCounterIdx};
end

dlgdata.counterData = counterData;
dlgdata.counterInfo = counterInfo;


%--------------------------------------------------------------------------
% FcnAddAlarm creates new alarm with default data
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag =1, if new alarm is created, =0 otherwise
%--------------------------------------------------------------------------
function [dlgdata, bModified] = FcnAddAlarm(dlgdata)

% initialize return value
bModified = 0;

% ask user for alarm name
prompt   = 'Please enter a name for the alarm.';
dlgTitle = 'Alarm Name';
lineNum  = 1;
newAlarmName = tl_deblank(char(inputdlg(prompt,dlgTitle,lineNum)),3);
if isempty(newAlarmName),
    return;
end

alarmData = dlgdata.alarmData;

% check if alarm name is really new
alarmNameList = dlgdata.alarmInfo.dataStrings;
if any(strcmp(newAlarmName,alarmNameList));
    return
end

% check if current alarm is invalid and can be overwritten
currentAlarm    = dlgdata.data.alarm;
currentAlarmIdx = find(strcmp(currentAlarm,alarmNameList));
if alarmData(currentAlarmIdx).bValid || strcmp(currentAlarm, ' ')
    currentAlarmIdx = length(alarmNameList) + 1;
end
dlgdata.data.alarm = newAlarmName;

% initialize properties to default
alarmData = FcnSetAlarmDefaults(alarmData,currentAlarmIdx);

% add new alarm to alarmlist
dlgdata.alarmInfo.dataStrings(currentAlarmIdx) = {newAlarmName};

% append alarm to list of new alarms
dlgdata.alarmInfo.addedAlarm = unique([dlgdata.alarmInfo.addedAlarm,newAlarmName]);
bModified = 1;

dlgdata.alarmData = alarmData;

%--------------------------------------------------------------------------
% FcnDeleteAlarm remove current alarm
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnDeleteAlarm(dlgdata)

alarmData = dlgdata.alarmData;
alarmInfo = dlgdata.alarmInfo;

% get relevant indices
alarmList = alarmInfo.dataStrings;
delAlarm  = dlgdata.data.alarm;
delAlarmIdx = find(strcmp(delAlarm,alarmList));

% add alarms to list of deleted alarms
alarmInfo.deletedAlarm = unique([alarmInfo.deletedAlarm,delAlarm]);

% remove alarm from list of added alarms
idx = find(strcmp(delAlarm,alarmInfo.addedAlarm));
if ~isempty(idx),
    alarmInfo.addedAlarm(idx) = [];
end

% purge property struct
alarmInfo.dataStrings(delAlarmIdx) = [];
alarmData(delAlarmIdx) = [];

% update current element
numElements = length(alarmInfo.dataStrings);
if delAlarmIdx > numElements,
    if numElements,
        % at least one element remained
        dlgdata.data.alarm = alarmInfo.dataStrings{numElements};
    else
        % no elements
        dlgdata.data.alarm = ' ';
        alarmInfo.dataStrings = {' '};
        alarmData = FcnSetAlarmDefaults([],1);
        alarmData(1).bValid = 0;
    end
else
    dlgdata.data.alarm = alarmInfo.dataStrings{delAlarmIdx};
end

dlgdata.alarmData = alarmData;
dlgdata.alarmInfo = alarmInfo;


%-------------------------------------------------------
% FcnSetCounterDefaults
%   creates default data structure for counters
%
% INPUT ARGUMENTS
%   counterData     current counter data struct
%   idx             index of current counter
%
% OUTPUT ARGUMENTS
%   counterData     initialized counter data structure
%-------------------------------------------------------
function counterData = FcnSetCounterDefaults(counterData,idx)

counterData(idx).usedassystemtimer          = 0;
counterData(idx).omitcounterinitialization  = 1;
counterData(idx).maxallowedvalue            = 0;
counterData(idx).mincycle                   = 0;
counterData(idx).ticksperbase               = 0;
counterData(idx).tickduration               = -1;
counterData(idx).bValid                     = 1;


%--------------------------------------------------------------------------
% FcnUpdateCounterAlarmControls updates the controls of the alarm tab
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number (=1 for alarm page)
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateCounterAlarmControls(dlgdata, dlgfig, pageNum)

Children = dlgdata.pageData{pageNum}.children;

alarmData = dlgdata.alarmData;

% get task list
taskList = dsdd('GetChildrenNames','/Pool/RTOS/Tasks');
if isempty(taskList),
    taskList = {' '};
else
    taskList = [{' '}, taskList];
end
% get event list
eventList = dsdd('GetChildrenNames','/Pool/RTOS/Events');
if isempty(eventList),
    eventList = {' '};
else
    eventList = [{' '}, eventList];
end

currentAlarm = dlgdata.data.alarm;
alarmList    = dlgdata.alarmInfo.dataStrings;
currentAlarmIdx = find(strcmp(currentAlarm,alarmList));

% default control status for action controls of alarms groupbox
alarmPopupCtrlStatus            = struct('enable', 'on', 'value', currentAlarmIdx, 'string', {alarmList});
addAlarmButtonCtrlStatus        = struct('enable', 'on');
deleteAlarmButtonCtrlStatus     = struct('enable', 'on');
absAlarmRadiobuttonCtrlStatus   = struct('enable', 'on', 'value', dlgdata.data.alarmkind == 1);
relAlarmRadiobuttonCtrlStatus   = struct('enable', 'on', 'value', dlgdata.data.alarmkind == 2);
startAlarmEditCtrlStatus        = struct('enable', 'on', 'string', num2str(dlgdata.data.startalarmportwidth));
startAlarmUpButtonCtrlStatus    = struct('enable', 'on');
startAlarmDownButtonCtrlStatus  = struct('enable', flag2str(dlgdata.data.startalarmportwidth > 1));
cancelAlarmEditCtrlStatus       = struct('enable', 'on', 'string', num2str(dlgdata.data.cancelalarmportwidth));
cancelAlarmUpButtonCtrlStatus   = struct('enable', 'on');
cancelAlarmDownButtonCtrlStatus = struct('enable', flag2str(dlgdata.data.cancelalarmportwidth > 1));

% default control status for action controls of alarms groupbox
autoActionAssignmentCheckboxCtrlStatus  = struct('enable', 'on', 'value', 1);
activateTaskRadiobuttonCtrlStatus       = struct('enable', 'on', 'value', 0);
setEventRadiobuttonCtrlStatus           = struct('enable', 'on', 'value', 0);
callbackRadiobuttonCtrlStatus           = struct('enable', 'on', 'value', 0);
activateTaskPopupCtrlStatus             = struct('enable', 'on', 'value', 1, 'string', ' ');
setEventPopupCtrlStatus                 = struct('enable', 'on', 'value', 1, 'string', ' ');
callbackEditCtrlStatus                  = struct('enable', 'on', 'string', '');

if ~isempty(currentAlarmIdx) && alarmData(currentAlarmIdx).bValid == 0,
    alarmPopupCtrlStatus.iserror = 1;

    % disable all action controls
    autoActionAssignmentCheckboxCtrlStatus.enable = 'off';
    activateTaskRadiobuttonCtrlStatus.enable = 'off';
    setEventRadiobuttonCtrlStatus.enable = 'off';
    callbackRadiobuttonCtrlStatus.enable = 'off';
    activateTaskPopupCtrlStatus.enable = 'off';
    setEventPopupCtrlStatus.enable = 'off';
    callbackEditCtrlStatus.enable = 'off';

    % disable delete button
    deleteAlarmButtonCtrlStatus.enable = 'off';
else
    if ~alarmData(currentAlarmIdx).autoactionassignment
        autoActionAssignmentCheckboxCtrlStatus.value = 0;
        switch alarmData(currentAlarmIdx).actionkind
            case {'ACTIVATETASK',''}
                activateTaskRadiobuttonCtrlStatus.value = 1;
                task = alarmData(currentAlarmIdx).task;
                if ~any(strcmp(task,taskList)),
                    taskList = [{task},taskList];
                    activateTaskPopupCtrlStatus.iserror = 1;
                    activateTaskPopupCtrlStatus.value = 1;
                else
                    activateTaskPopupCtrlStatus.value = find(strcmp(task,taskList));
                end
                activateTaskPopupCtrlStatus.string = taskList;
                setEventPopupCtrlStatus.enable = 'off';
                callbackEditCtrlStatus.enable = 'off';
            case 'SETEVENT'
                setEventRadiobuttonCtrlStatus.value = 1;
                task = alarmData(currentAlarmIdx).task;
                if ~any(strcmp(task,taskList)),
                    taskList = [{task},taskList];
                    activateTaskPopupCtrlStatus.iserror = 1;
                    activateTaskPopupCtrlStatus.value = 1;
                else
                    activateTaskPopupCtrlStatus.value = find(strcmp(task,taskList));
                end
                activateTaskPopupCtrlStatus.string = taskList;
                event = alarmData(currentAlarmIdx).event;
                if ~any(strcmp(event,eventList)),
                    eventList = [{event},eventList];
                    setEventPopupCtrlStatus.iserror = 1;
                    setEventPopupCtrlStatus.value = 1;
                else
                    setEventPopupCtrlStatus.value = find(strcmp(event,eventList));
                end
                setEventPopupCtrlStatus.string = eventList;
                callbackEditCtrlStatus.enable = 'off';
            case 'CALLBACK'
                callbackRadiobuttonCtrlStatus.value = 1;
                callbackEditCtrlStatus.string = alarmData(currentAlarmIdx).callbackfcn;
                activateTaskPopupCtrlStatus.enable = 'off';
                setEventPopupCtrlStatus.enable = 'off';
        end
    else
        autoActionAssignmentCheckboxCtrlStatus.value = 1;
        activateTaskRadiobuttonCtrlStatus.enable = 'off';
        setEventRadiobuttonCtrlStatus.enable = 'off';
        callbackRadiobuttonCtrlStatus.enable = 'off';
        activateTaskPopupCtrlStatus.enable = 'off';
        setEventPopupCtrlStatus.enable = 'off';
        callbackEditCtrlStatus.enable = 'off';
    end
end

% update counter groupbox
currentCounter = alarmData(currentAlarmIdx).counterRef;
counterList    = dlgdata.counterInfo.dataStrings;
currentCounterIdx = find(strcmp(currentCounter,counterList));
if isempty(currentCounterIdx)
    currentCounterIdx = 1;
    counterList = [currentCounter counterList];
end
counterData    = dlgdata.counterData;

% default control status for  controls of counters groupbox
counterPopupCtrlStatus              = struct('enable', 'on', 'value', currentCounterIdx, 'string', {counterList});
addCounterButtonCtrlStatus          = struct('enable', 'on');               %#ok
deleteCounterButtonCtrlStatus       = struct('enable', 'on');
usedAsSystemTimerCheckboxCtrlStatus = struct('enable', 'on');
omitCounterInitializationCheckboxCtrlStatus  = struct('enable', 'on');
maxAllowedValueEditCtrlStatus       = struct('enable', 'on');
maxAllowedValueTextCtrlStatus       = struct('enable', 'on', 'string', FcnNum2Str(0,0));
minCycleEditCtrlStatus              = struct('enable', 'on');
minCycleTextCtrlStatus              = struct('enable', 'on', 'string', FcnNum2Str(0,0));
ticksPerBaseEditCtrlStatus          = struct('enable', 'on');
tickDurationEditCtrlStatus          = struct('enable', 'on');
tickDurationInSimulationEditCtrlStatus = struct('enable', 'on', 'string', num2str(dlgdata.data.tickdurationinsimulation));

if strcmp(currentCounter, ' ') || (~isempty(currentCounterIdx) && counterData(currentCounterIdx).bValid == 0)
    counterPopupCtrlStatus.iserror = 1;

    % disable counter controls
    usedAsSystemTimerCheckboxCtrlStatus.enable = 'off';
    omitCounterInitializationCheckboxCtrlStatus.enable = 'off';
    maxAllowedValueEditCtrlStatus.enable = 'off';
    minCycleEditCtrlStatus.enable = 'off';
    ticksPerBaseEditCtrlStatus.enable = 'off';
    tickDurationEditCtrlStatus.enable = 'off';

    % disable delete button
    deleteCounterButtonCtrlStatus.enable = 'off';
else
    counterPopupCtrlStatus.value  = currentCounterIdx;
    counterPopupCtrlStatus.string = counterList;

    usedAsSystemTimerCheckboxCtrlStatus.value = ...
        counterData(currentCounterIdx).usedassystemtimer;
    omitCounterInitializationCheckboxCtrlStatus.value = ...
        counterData(currentCounterIdx).omitcounterinitialization;
    maxAllowedValueEditCtrlStatus.string = ...
        num2str(counterData(currentCounterIdx).maxallowedvalue);
    minCycleEditCtrlStatus.string = ...
        num2str(counterData(currentCounterIdx).mincycle);
    ticksPerBaseEditCtrlStatus.string = ...
        num2str(counterData(currentCounterIdx).ticksperbase);
    tickDurationEditCtrlStatus.string = ...
        num2str(counterData(currentCounterIdx).tickduration);
    tickDurationInSimulationEditCtrlStatus.string = ...
        num2str(dlgdata.data.tickdurationinsimulation);
    % tick duration -1 is not allowed if counter is used as system timer
    bInvalid = counterData(currentCounterIdx).usedassystemtimer == 1 ...
        && (counterData(currentCounterIdx).tickduration <= 0 ...
        || isinf(counterData(currentCounterIdx).tickduration));
    tickDurationEditCtrlStatus.iserror = bInvalid;

    maxAllowedValueTextCtrlStatus.string = FcnNum2Str(counterData(currentCounterIdx).tickduration, ...
        counterData(currentCounterIdx).maxallowedvalue);
    minCycleTextCtrlStatus.string = FcnNum2Str(counterData(currentCounterIdx).tickduration, ...
        counterData(currentCounterIdx).mincycle);
end

dlgdata.alarmData = alarmData;
dlgdata.counterData = counterData;

ctrlsList = {
    'alarmPopup' ...
    'addAlarmButton' ...
    'deleteAlarmButton' ...
    'relAlarmRadiobutton' ...
    'absAlarmRadiobutton' ...
    'startAlarmEdit' ...
    'startAlarmUpButton' ...
    'startAlarmDownButton' ...
    'cancelAlarmEdit' ...
    'cancelAlarmUpButton' ...
    'cancelAlarmDownButton' ...
    'autoActionAssignmentCheckbox' ...
    'activateTaskRadiobutton' ...
    'setEventRadiobutton' ...
    'callbackRadiobutton' ...
    'activateTaskPopup' ...
    'setEventPopup' ...
    'callbackEdit' ...
    'counterPopup' ...
    'addCounterButton' ...
    'deleteCounterButton' ...
    'usedAsSystemTimerCheckbox' ...
    'omitCounterInitializationCheckbox' ...
    'maxAllowedValueEdit' ...
    'maxAllowedValueText' ...
    'minCycleEdit' ...
    'minCycleText' ...
    'ticksPerBaseEdit' ...
    'tickDurationEdit' ...
    'tickDurationInSimulationEdit'};

for ctrlsNo=1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
    set(ctrl, 'UserData', UserData);
end
TLSetCtrlsStatus(dlgfig,Children, ctrlsList);


%-------------------------------------------------------
% FcnGetDataFromDD
%   gets all necessary data of alarms and depending counters from DD and
%   puts it into an additional field 'alarmData' of dlgdata
%
% INPUT ARGUMENTS
%   dlgdata      dialog data structure
%
% OUTPUT ARGUMENTS
%   dlgdata      modified dialog data structure
%-------------------------------------------------------
function dlgdata = FcnGetDataFromDD(dlgdata)

% initialize lists holding added and deleted counters and alarms
counterInfo.addedCounter   = {};
counterInfo.deletedCounter = {};
counterInfo.editedCounter  = {};
alarmInfo.addedAlarm     = {};
alarmInfo.deletedAlarm   = {};
alarmInfo.editedAlarm    = {};

currentAlarm = dlgdata.data.alarm;
%---------------------------------------
% retrieve alarm from Data Dictionary
%---------------------------------------

% alarms are stored in RTOS branch of Data Dictionary pool
[hAlarm,errCode] = dsdd('GetChildren','/Pool/RTOS/Alarms');
if dsdd_check_msg(errCode),
    return
end
if isempty(hAlarm),
    alarmNameList = {currentAlarm};
    alarmIdx = 1;
    alarmData = FcnSetAlarmDefaults([],alarmIdx);
    % mark alarm as not valid
    alarmData.bValid = 0;
else
    % initialize alarm data structure
    alarmNameList = cell(1, length(hAlarm));
    alarmData(1:length(hAlarm)) = FcnSetAlarmDefaults([],1);
    for idx = 1:length(hAlarm),
        alarmName = dsdd('GetAttribute',hAlarm(idx),'Name');
        alarmNameList{idx} = alarmName;
        hAction = dsdd('GetAction',hAlarm(idx));
        counterRef = dsdd('GetCounterRef',hAlarm(idx));
        if isempty(counterRef),
            counterRef = ' ';
        else
            % remove the default path from string
            if strncmp(counterRef,'//DD0/Pool/RTOS/Counters/',25)
                counterRef = counterRef(min(26,end):end);
            elseif  strncmp(counterRef,'/Pool/RTOS/Counters/',20)
                counterRef = counterRef(min(21,end):end);
            end
        end
        alarmData(idx).counterRef = counterRef;
        alarmData(idx).autoactionassignment = ...
            dsdd('GetAutomaticActionAssignment',hAlarm(idx));
        % properties from embedded action object
        actionKind = dsdd('GetActionKind',hAction);
        alarmData(idx).actionkind  = actionKind;
        alarmData(idx).task        = ' ';
        alarmData(idx).event       = ' ';
        alarmData(idx).callbackfcn = '';
        switch actionKind
            case 'ACTIVATETASK'
                task = dsdd('GetTaskRef',hAction);
                if isempty(task),
                    task = ' ';
                end
                alarmData(idx).task = task;
            case 'SETEVENT'
                task = dsdd('GetTaskRef',hAction);
                if isempty(task),
                    task = ' ';
                end
                alarmData(idx).task = task;
                event = dsdd('GetEventRef',hAction);
                if isempty(event),
                    event = ' ';
                end
                alarmData(idx).event = event;
            case 'CALLBACK'
                alarmData(idx).callbackfcn = ...
                    dsdd('GetCallbackName',hAction);
            case 'NONE'
                % do nothing
            otherwise
                ds_error_msg('Internal error: unsupported action kind');
        end
        alarmData(idx).bValid = 1;
    end
    % check if current alarm is a member of alarm list
    alarmIdx = find(strcmp(currentAlarm,alarmNameList));
    if isempty(alarmIdx),
        alarmNameList = [alarmNameList,{currentAlarm}];
        alarmIdx = length(alarmNameList);
        alarmData = FcnSetAlarmDefaults(alarmData,alarmIdx);
        % mark alarm as not valid
        alarmData(alarmIdx).bValid = 0;
    end
end

alarmInfo.dataStrings = alarmNameList;

currentCounter = alarmData(alarmIdx).counterRef;
%---------------------------------------
% retrieve counters from Data Dictionary
%---------------------------------------

% counters are stored in RTOS branch of Data Dictionary pool
[hCounter,errCode] = dsdd('GetChildren','/Pool/RTOS/Counters');
if dsdd_check_msg(errCode),
    return
end

if isempty(hCounter),
    counterNameList = {currentCounter};
    counterIdx = 1;
    counterData = FcnSetCounterDefaults([],counterIdx);
    % mark counter as not valid
    counterData.bValid = 0;
else
    % initialize counter data structure
    counterNameList = cell(1, length(hCounter));
    counterData(1:length(hCounter)) = FcnSetCounterDefaults([],1);
    for idx = 1:length(hCounter),
        counterName = dsdd('GetAttribute',hCounter(idx),'Name');
        counterNameList{idx} = counterName;
        counterData(idx).usedassystemtimer = ...
            dsdd('GetSystemTimer',hCounter(idx));
        counterData(idx).omitcounterinitialization = ...
            dsdd('GetOmitCounterInitialization',hCounter(idx));
        counterData(idx).maxallowedvalue = ...
            dsdd('GetMaxAllowedValue',hCounter(idx));
        counterData(idx).mincycle = ...
            dsdd('GetMinCycle',hCounter(idx));
        counterData(idx).ticksperbase = ...
            dsdd('GetTicksPerBase',hCounter(idx));
        counterData(idx).tickduration = ...
            dsdd('GetTickDuration',hCounter(idx));
        counterData(idx).bValid = 1;
    end
end

% check if current counter is a member of counter list
counterIdx = find(strcmp(currentCounter,counterNameList), 1);
if isempty(counterIdx),
    counterNameList = [counterNameList,{currentCounter}];
    counterIdx = length(counterNameList);
    counterData = FcnSetAlarmDefaults(counterData,counterIdx);
    % mark counter as not valid
    counterData(counterIdx).bValid = 0;
end
counterInfo.dataStrings = counterNameList;

dlgdata.alarmData = alarmData;
dlgdata.alarmInfo = alarmInfo;
dlgdata.counterData = counterData;
dlgdata.counterInfo = counterInfo;


%-------------------------------------------------------
% FcnSetAlarmDefaults
%   creates default data structure for alarms
%
% INPUT ARGUMENTS
%   alarmData       current alarm data struct
%   idx             index of current alarm
%
% OUTPUT ARGUMENTS
%   alarmData      initialized alarm data structure
%-------------------------------------------------------
function alarmData = FcnSetAlarmDefaults(alarmData,idx)

alarmData(idx).autoactionassignment  = 1;
alarmData(idx).actionkind            = 'ACTIVATETASK';
alarmData(idx).task                  = ' ';
alarmData(idx).event                 = ' ';
alarmData(idx).callbackfcn           = '';
alarmData(idx).counterRef            = ' ';
alarmData(idx).bValid                = 1;


%--------------------------------------------------------------------------
% FcnApply writes current block data to the DD
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   - / -
%--------------------------------------------------------------------------
function FcnApply(dlgdata)

% apply changes to counter objetcs
counterInfo = dlgdata.counterInfo;

% counters are located under Pool/RTOS/Counters
ddPath = '/Pool/RTOS/Counters';
[bExist,hCounterNode] = dsdd('Exist',ddPath);
if ~bExist,
    ds_error_msg(['Assertion failure in ',mfilename]);
end

% first delete counters
for m = 1:length(counterInfo.deletedCounter),
    [bExist,hCounter] = dsdd('Exist',counterInfo.deletedCounter{m}, ...
        'Parent',hCounterNode);
    if bExist,
        dsdd('Delete',hCounter);
    end
end

% add newly inserted counters
for m = 1:length(counterInfo.addedCounter),
    dsdd('Create',counterInfo.addedCounter{m}, ...
        'Parent',            hCounterNode, ...
        'ObjectKind',        'Counter');
    % don't return if creation failed; changes of counter are not saved in block data
    % append created counters to edited counter
    counterInfo.editedCounter = [counterInfo.editedCounter,counterInfo.addedCounter(m)];
end

% apply changes of edited counters
editedCounter = unique(counterInfo.editedCounter);
for m = 1:length(editedCounter),
    idx = strcmp(editedCounter{m},counterInfo.dataStrings);
    [bExist,hCounter] = dsdd('Exist',editedCounter{m}, ...
        'Parent',         hCounterNode);
    properties = dlgdata.counterData(idx);
    if bExist,
        [errCode] = dsdd('SetSystemTimer',hCounter,properties.usedassystemtimer);
        dsdd_check_msg(errCode);
        [errCode] = dsdd('SetOmitCounterInitialization',hCounter, ...
            properties.omitcounterinitialization);
        dsdd_check_msg(errCode);
        [errCode] = dsdd('SetMaxAllowedValue',hCounter,properties.maxallowedvalue);
        dsdd_check_msg(errCode);
        [errCode] = dsdd('SetMinCycle',hCounter,properties.mincycle);
        dsdd_check_msg(errCode);
        [errCode] = dsdd('SetTicksPerBase',hCounter,properties.ticksperbase);
        dsdd_check_msg(errCode);
        [errCode] = dsdd('SetTickDuration',hCounter,properties.tickduration);
        dsdd_check_msg(errCode);
    end
end

% apply changes to alarm objetcs
alarmInfo = dlgdata.alarmInfo;

% data must be writen to data dictionary
ddPath = '/Pool/RTOS/Alarms';
[bExist,hAlarmNode] = dsdd('Exist',ddPath);
if ~bExist
    ds_error_msg(['Assertion failure in ', mfilename]);
end

% first delete alarms
for m = 1:length(alarmInfo.deletedAlarm),
    [bExists,hAlarm] = dsdd('Exist',alarmInfo.deletedAlarm{m}, ...
        'Parent',hAlarmNode);
    if bExist,
        dsdd('Delete',hAlarm);
    end
end

% add newly inserted alarms
for m = 1:length(alarmInfo.addedAlarm),
    dsdd('Create',alarmInfo.addedAlarm{m}, ...
        'Parent',            hAlarmNode, ...
        'ObjectKind',        'Alarm');
    % don't return if creation failed; alarmlist not saved in block data
    % append created alarm to edited alarms
    alarmInfo.editedAlarm = [alarmInfo.editedAlarm,alarmInfo.addedAlarm(m)];
end

% apply changes of edited alarms
editedAlarm = unique(alarmInfo.editedAlarm);
for m = 1:length(editedAlarm),
    idx = strcmp(editedAlarm{m},alarmInfo.dataStrings);
    [bExist,hAlarm] = dsdd('Exist',editedAlarm{m}, ...
        'Parent',         hAlarmNode);
    properties = dlgdata.alarmData(idx);
    if bExist,
        [errCode] = dsdd('SetCounterRef',hAlarm,properties.counterRef);
        dsdd_check_msg(errCode);
        [errCode] = dsdd('SetAutomaticActionAssignment',hAlarm,properties.autoactionassignment);
        dsdd_check_msg(errCode);
        % properties from embedded action object
        hAction = dsdd('GetAction',hAlarm);
        % WORKAROUND
        if isempty(properties.actionkind)
            continue
        else
            [errCode] = dsdd('SetActionKind',hAction,properties.actionkind);
            dsdd_check_msg(errCode);
        end
        % set task reference at action object
        task = tl_deblank(properties.task,2);
        if ~isempty(task),
            [errCode] = dsdd('SetTaskRef',hAction,task);
            dsdd_check_msg(errCode);
        end
        % set event reference at action object
        event = tl_deblank(properties.event,2);
        if ~isempty(event),
            [errCode] = dsdd('SetEventRef',hAction,event);
            dsdd_check_msg(errCode);
        end
        % set callback function at action object
        callbackfcn = tl_deblank(properties.callbackfcn,2);
        if ~isempty(callbackfcn),
            [errCode] = dsdd('SetCallbackName',hAction,callbackfcn);
            dsdd_check_msg(errCode);
        end
    end
end


%--------------------------------------------------------------------------
% FcnNum2Str creates unit string for counter settings
%
% INPUT ARGUMENTS
%   tickDuration    value of tick duration
%   value           current field value
%
% OUTPUT ARGUMENTS
%   unitStr         calculated unit string for current field
%--------------------------------------------------------------------------
function unitStr = FcnNum2Str(tickDuration,value)

% simple case: tick duration = -1
if tickDuration == -1,
    unitStr = 'Ticks';
    return
end

% calculate value
dispValue = tickDuration * value;
if dispValue == 0,
    unitStr = 'x Tick duration = 0 s';
elseif dispValue > 60,
    % display value in seconds, minutes, hours
    dd = fix(dispValue / 86400);
    dispValue = dispValue - dd * 86400;
    hh = fix(dispValue / 3600);
    dispValue = dispValue - hh * 3600;
    mm = fix(dispValue / 60);
    ss = round(dispValue - mm * 60);
    timeStr = sprintf('%02d:%02d:%02d:%02d',dd,hh,mm,ss);
    unitStr = ['x Tick duration = ',timeStr];
else
    % display in engineering format
    siPrefix = {'','m','n','p','f'};
    idx = abs(floor(log10(dispValue)/3)) + 1;
    man = dispValue * 10^(3*(idx-1));
    timeString = sprintf('%.2f %ss',man,siPrefix{idx});
    unitStr = ['x Tick duration = ',timeString];
end

%-----------------------------------------------------------------------------------------
% FcnSaveCtrlUserData saves UserData at controls
%
% INPUT ARGUMENTS
%   Children     Structure with controls
%   ctrl         Control for which the status is set
%   ctrlStatus   Status of this control
%-----------------------------------------------------------------------------------------
function FcnSaveCtrlUserData(ctrlsStruct, ctrlsList, ctrlData)                  %#ok

% set status to control
for ctrlsNo = 1 : length(ctrlsList)
    hCtrl = eval(['ctrlsStruct.', ctrlsList{ctrlsNo}]);
    UserData = get(hCtrl, 'UserData');
    fieldNames = fields(ctrlData);
    for fieldNo = 1 : length(fieldNames)
        switch fieldNames{fieldNo}
            case 'enable'
                UserData.ctrlStatus.enable = ctrlData.enable;
            case 'iserror'
                UserData.ctrlStatus.iserror = ctrlData.iserror;
            case 'string'
                UserData.ctrlStatus.string = ctrlData.string;
            case 'value'
                UserData.ctrlStatus.value = ctrlData.value;
        end
    end
    set(hCtrl, 'UserData', UserData);
end
